#include "jpg.h"
#include "lcd.h"

void load_jpg(const char *jpgname, struct jpeg_info *p)
{
    // 将在jpeg数据到p指向的结构体中
    p->filename = jpgname;
    FILE *fp = fopen(jpgname, "r"); // xxx.jpg

    struct stat st;
    bzero(&st, sizeof(st));
    stat(jpgname, &st);

    p->jpg_size = st.st_size; // JPG图片的大小
    p->jpg_data = malloc(p->jpg_size);

    int n = fread(p->jpg_data, p->jpg_size, 1, fp);
    if(n == 1)
        return;

    if(n < 1)
        perror("加载JPEG图片失败");
    
    fclose(fp);
    return;
}

struct jpeg_info *jpg2rgb(const char *jpgfile)
{
    static struct jpeg_info jinfo;

    // 0，加载jpeg文件，得到jpg_data
    load_jpg(jpgfile, &jinfo);

    // 1，声明解码结构体，以及错误管理结构体
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;

    // 2，使用缺省的出错处理来初始化解码结构体
    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_decompress(&cinfo);

    // 3，配置该cinfo，使其从 jpgdata 中读取jpgsize个字节
    //    这些数据必须是完整的JPEG数据
    jpeg_mem_src(&cinfo, jinfo.jpg_data, jinfo.jpg_size);

    // 4，读取JPEG文件的头，并判断其格式是否合法
    if(!jpeg_read_header(&cinfo, true))
    {
        fprintf(stderr, "jpeg_read_header failed: "
            "%s\n", strerror(errno));
        return NULL;
    }

    // 5，开始解码
    jpeg_start_decompress(&cinfo);

    // 6，显示并保存图片的尺寸信息
    printf("宽：  %d\n", jinfo.width  = cinfo.output_width);
    printf("高：  %d\n", jinfo.height =  cinfo.output_height);
    printf("色深：%d\n", jinfo.bpp    =  cinfo.output_components);


    // 计算一行的字节数
    int row_stride = jinfo.width * jinfo.bpp/8;

    // 7，根据图片的尺寸大小，分配一块相应的内存rgbdata
    //    用来存放从jpgdata解码出来的图像数据
    unsigned long linesize = cinfo.output_width * cinfo.output_components;
    jinfo.rgb_size  = linesize * cinfo.output_height;
    jinfo.rgb_data  = calloc(1, jinfo.rgb_size);

    // 8，循环地将图片的每一行读出并解码到rgb_buffer中
    int line = 0;
    while(cinfo.output_scanline < cinfo.output_height)
    {
        unsigned char *buffer_array[1];
        buffer_array[0] = jinfo.rgb_data + cinfo.output_scanline * linesize;
        jpeg_read_scanlines(&cinfo, buffer_array, 1);
    }

    // 9，解码完了，将jpeg相关的资源释放掉
    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);

    free(jinfo.jpg_data);
    return &jinfo;
}

void display_jpg(const char *jpgname, struct LCD_info *lcd_info, uint8_t mode)
{
    struct jpeg_info *jinfo = jpg2rgb(jpgname);
    // 解析一下用户的显示图片的模式
    bool zoom;
    zoom=(jinfo->width>lcd_info->width || jinfo->height>lcd_info->height);
    zoom =zoom && (mode & ZOOM);// 在图片大于LCD尺寸条件下用户要求缩小才缩小

    

    int jpg_w = zoom ? jinfo->width/2 : jinfo->width;
    int jpg_h = zoom ? jinfo->height/2: jinfo->height;
    int x = (lcd_info->width-jinfo->width)/2;
    int y = (lcd_info->height-jinfo->height)/2;

    bool center;
    center = (jpg_w<lcd_info->width || jpg_h<lcd_info->height);
    center =center && (mode &CENTER);

    char *fbm =lcd_info->fb_mem + (center ? (y*800+x)*4 : 0);

    int lcd_w=center ? lcd_info->width -x : lcd_info->width;
    int lcd_h=center ? lcd_info->height -y : lcd_info->height;

    printf("zoom:   %d\n", zoom);
    printf("center: %d\n", center);

    printf("lcd_w:%d\n", lcd_w);
    printf("lcd_h:%d\n", lcd_h);

    // 3. 显示JPEG
    for(int j=0,m=0; j<lcd_h && m<jinfo->height; j++,zoom?(m+=2):m++)
    {
        for(int i=0,k=0; i<lcd_w && k<jinfo->width; i++,zoom?(k+=2):k++)
        {
            // memcpy(lcd_info->fb_mem+4*i + 800*4*j, jinfo->rgb_data+3*i + jinfo->width*3*j, 3);
            memcpy(fbm+4*i + 800*4*j+2, jinfo->rgb_data+k*3 + jinfo->width*3*m+0, 1);
            memcpy(fbm+4*i + 800*4*j+1, jinfo->rgb_data+k*3 + jinfo->width*3*m+1, 1);
            memcpy(fbm+4*i + 800*4*j+0, jinfo->rgb_data+k*3 + jinfo->width*3*m+2, 1);
        }
    }

    free(jinfo->rgb_data);
}